/*
 * HTDrawNode.java
 * www.bouthier.net
 *
 * The MIT License :
 * -----------------
 * Copyright (c) 2001 Christophe Bouthier
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package hypertree.model;

import java.awt.Color;
import java.awt.Graphics2D;


/**
 * The HTDrawNode class contains the drawing coordinates of a HTModelNode for
 * the HTView. It implements the Composite design pattern.
 * 
 * @author Christophe Bouthier [bouthier@loria.fr]
 * @version 1.0
 */
public class HTDrawNode
{

	@SuppressWarnings("unused")
	private HTDraw				model			= null;	// drawing model
	private HTModelNode			node			= null;	// encapsulated
	// HTModelNode

	private HTCoordE			ze				= null;	// current euclidian
	// coords
	private HTCoordE			oldZe			= null;	// old euclidian coords
	protected HTCoordS			zs				= null;	// current screen coords

	private HTDrawNodeComposite	father			= null;	// father of this node
	private HTDrawNode			brother			= null;	// brother of this node

	private HTNodeLabel			label			= null;	// label of the node

	protected boolean			fastMode		= false;	// fast mode
	protected boolean			longNameMode	= false;	// long name
	// displayed
	protected boolean			kleinMode		= false;	// klein mode

	/* --- Constructor --- */

	/**
	 * Constructor.
	 * 
	 * @param father
	 *            the father of this node
	 * @param node
	 *            the encapsulated HTModelNode
	 * @param model
	 *            the drawing model
	 */
	public HTDrawNode(HTDrawNodeComposite father, HTModelNode node, HTDraw model)
	{
		this.father = father;
		this.node = node;
		this.model = model;

		this.label = new HTNodeLabel(this);

		this.ze = new HTCoordE(node.getCoordinates());
		this.oldZe = new HTCoordE(this.ze);
		this.zs = new HTCoordS();
	}

	/* --- Brother --- */

	/**
	 * Sets the brother of this node.
	 * 
	 * @param brother
	 *            the borther of this node
	 */
	public void setBrother(HTDrawNode brother)
	{
		this.brother = brother;
	}

	/* --- Encapsulated HYModelNode --- */

	/**
	 * Returns the encapsulated HTModelNode.
	 * 
	 * @return the encapsulated HTModelNode
	 */
	public HTModelNode getHTModelNode()
	{
		return this.node;
	}

	/* --- Color --- */

	/**
	 * Returns the color of the node.
	 * 
	 * @return the color of the node
	 */
	public Color getColor()
	{
		return this.node.getNode().getColor();
	}

	/* --- Name --- */

	/**
	 * Returns the name of this node.
	 * 
	 * @return the name of this node
	 */
	public String getName()
	{
		return this.node.getName();
	}

	/* --- Coordinates --- */

	/**
	 * Returns the current coordinates of this node. WARNING : this is NOT a
	 * copy but the true object (for performance).
	 * 
	 * @return the current coordinates
	 */
	public HTCoordE getCoordinates()
	{
		return this.ze;
	}

	public HTCoordE getOldCoordinates()
	{
		return this.oldZe;
	}

	public HTCoordS getScreenCoordinates()
	{
		return this.zs;
	}

	/**
	 * Refresh the screen coordinates of this node.
	 * 
	 * @param sOrigin
	 *            the origin of the screen plane
	 * @param sMax
	 *            the (xMax, yMax) point in the screen plane
	 */
	public void refreshScreenCoordinates(HTCoordS sOrigin, HTCoordS sMax)
	{
		if (this.kleinMode)
		{
			this.zs.projectionEtoS(this.ze.pToK(), sOrigin, sMax);
		} else
		{
			this.zs.projectionEtoS(this.ze, sOrigin, sMax);
		}
	}

	/* --- Drawing --- */

	/**
	 * Draws the branches from this node to its children. Overidden by
	 * HTDrawNodeComposite
	 * 
	 * @param g
	 *            the graphic context
	 */
	public void drawBranches(Graphics2D g)
	{
	}

	/**
	 * Draws this node.
	 * 
	 * @param g
	 *            the graphic context
	 */
	public void drawNodes(Graphics2D g)
	{
		if (this.fastMode == false)
		{
			this.label.draw(g);
			//g.fillOval(x, y, width, height)
		}
	}

	/**
	 * Returns the minimal distance between this node and his father and his
	 * brother.
	 * 
	 * @return the minimal distance
	 */
	public int getSpace()
	{
		int dF = -1;
		int dB = -1;

		if (this.father != null)
		{
			HTCoordS zF = this.father.getScreenCoordinates();
			dF = this.zs.getDistance(zF);
		}
		if (this.brother != null)
		{
			HTCoordS zB = this.brother.getScreenCoordinates();
			dB = this.zs.getDistance(zB);
		}

		if ((dF == -1) && (dB == -1))
		{
			return -1;
		} else if (dF == -1)
		{
			return dB;
		} else if (dB == -1)
		{
			return dF;
		} else
		{
			return Math.min(dF, dB);
		}
	}

	/* --- Translation --- */

	/**
	 * Special transformation, optimized.
	 * 
	 * @param alpha
	 *            first member
	 * @param beta
	 *            second member
	 */
	public void specialTrans(HTCoordE alpha, HTCoordE beta)
	{
		this.ze.copy(this.oldZe);
		this.ze.specialTrans(alpha, beta);
	}

	/**
	 * Ends the translation.
	 */
	public void endTranslation()
	{
		this.oldZe.copy(this.ze);
	}

	/**
	 * Restores the hyperbolic tree to its origin.
	 */
	public void restore()
	{
		HTCoordE orig = this.node.getCoordinates();
		this.ze.x = orig.x;
		this.ze.y = orig.y;
		this.oldZe.copy(this.ze);
	}

	/**
	 * Sets the fast mode, where nodes are no more drawed.
	 * 
	 * @param mode
	 *            setting on or off.
	 */
	public void fastMode(boolean mode)
	{
		if (mode != this.fastMode)
		{
			this.fastMode = mode;
		}
	}

	/**
	 * Sets the long name mode, where full names are drawn.
	 * 
	 * @param mode
	 *            setting on or off.
	 */
	public void longNameMode(boolean mode)
	{
		if (mode != this.longNameMode)
		{
			this.longNameMode = mode;
		}
	}

	/**
	 * Sets the klein mode.
	 * 
	 * @param mode
	 *            setting on or off.
	 */
	public void kleinMode(boolean mode)
	{
		if (mode != this.kleinMode)
		{
			this.kleinMode = mode;
		}
	}

	/**
	 * Returns the long name mode.
	 * 
	 * @return is the long name mode on or off ?
	 */
	public boolean getLongNameMode()
	{
		return this.longNameMode;
	}

	/* --- Node searching --- */

	/**
	 * Returns the node (if any) whose screen coordinates' zone contains thoses
	 * given in parameters.
	 * 
	 * @param zs
	 *            the given screen coordinate
	 * @return the searched HTDrawNode if found; <CODE>null</CODE> otherwise
	 */
	public HTDrawNode findNode(HTCoordS zs)
	{
		if (this.label.contains(zs))
		{
			return this;
		} else
		{
			return null;
		}
	}

	/* --- ToString --- */

	/**
	 * Returns a string representation of the object.
	 * 
	 * @return a String representation of the object
	 */
	@Override
	public String toString()
	{
		String result = this.getName() + "\n\t" + this.ze + "\n\t" + this.zs;
		return result;
	}

}
